home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Utilities / ODDebug.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  11.7 KB  |  539 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ODDebug.cpp
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Owned by:    David McCusker
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     3/29/96    DM        1335889: add TRY block to _Warn() so
  13.                                     exceptions cannot propagate
  14.  
  15.     To Do:
  16. */
  17.  
  18. /*
  19.     File:        ODDebug.cpp
  20.  
  21.     Contains:    Useful debugging macros and functions.
  22.  
  23.     Owned by:    Jens Alfke
  24.  
  25.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  26.  
  27. */
  28.  
  29. #ifndef _ODDEBUG_
  30. #include "ODDebug.h"
  31. #endif
  32.  
  33. #ifndef _EXCEPT_
  34. #include "Except.h"
  35. #endif
  36.  
  37. #ifndef _PLFMDEF_
  38. #include "PlfmDef.h"
  39. #endif
  40.  
  41. #ifndef _PASCLSTR_
  42. #include "PasclStr.h"
  43. #endif
  44.  
  45. #ifndef _PLFMDEF_
  46. #include "PlfmDef.h"
  47. #endif
  48.  
  49. #ifndef _EXCEPT_
  50. #include "Except.h"
  51. #endif
  52.  
  53. #ifndef _TEXTUTILS_
  54. #include "TextUtils.h"
  55. #endif
  56.  
  57. #ifndef _CRAWL_
  58. #include "Crawl.h"
  59. #endif
  60.  
  61. #ifndef _USERSRCM_
  62. #include "UseRsrcM.h"
  63. #endif
  64.  
  65. #ifndef _DLOGUTIL_
  66. #include "DlogUtil.h"
  67. #endif
  68.  
  69. #ifndef _UTILDEFS_
  70. #include "UtilDefs.h"
  71. #endif
  72.  
  73. #include <somobj.xh>
  74. #include <somcls.xh>
  75.  
  76. #include <stdio.h>
  77. #include <stdarg.h>
  78. #include <string.h>
  79.  
  80.  
  81. const ODSShort kOutputBufferSize = 400;
  82.  
  83. static somTD_SOMOutCharRoutine    *gOld_SOMOutCharRoutine;
  84. static somTD_SOMError            *gOld_SOMError;
  85.  
  86. // The output buffer is circular. We keep two indices, one for the start
  87. // of the most recent string and one for the end (the current input position.)
  88. static char gOutputBuffer[kOutputBufferSize];
  89. static ODSShort gOutputStart = 0;
  90. static ODSShort gOutputEnd   = 0;
  91.  
  92. static DebugOutputMode gOutputMode = kNoOutput;
  93.  
  94.  
  95. void BREAK( const char[] );
  96.  
  97. static short    gOutputFile = kODNULL;
  98.  
  99. //=====================================================================================
  100. // ODInitExceptions
  101. //=====================================================================================
  102.  
  103.  
  104. extern "C" {
  105.     static int OD_SOMOutCharRoutine( char c );
  106.     static void OD_SOMError( int error, corbastring filename, int linenum );
  107. }
  108.  
  109.  
  110. void
  111. ODInitExceptions( )
  112. {
  113.     gOld_SOMOutCharRoutine    = SOMOutCharRoutine;
  114.     gOld_SOMError            = SOMError;
  115.     SOMOutCharRoutine        = OD_SOMOutCharRoutine;
  116.     SOMError                = OD_SOMError;
  117. //    SOM_WarnLevel            = 1; // all, from somcdev.h
  118. }
  119.  
  120.  
  121. //=====================================================================================
  122. // Output routines
  123. //=====================================================================================
  124.  
  125.  
  126. #ifdef _PLATFORM_MACINTOSH_
  127.  
  128. #ifndef __STRINGS__
  129. #include <Strings.h>
  130. #endif
  131.  
  132.  
  133. static OSErr
  134. SendToDebugWindow( const char buffer[], short length )
  135. {
  136.     // Code adapted from API to "DebugWindow" app by Keith Ledbetter
  137.     AEAddressDesc    address;
  138.     AppleEvent        appleEvent, reply;
  139.     OSType            targetSig;
  140.     OSErr            err;
  141.  
  142.     targetSig = 'LdbW';
  143.     err= AECreateDesc( typeApplSignature, (Ptr)&targetSig, 
  144.                         sizeof(targetSig), &address );
  145.     if( !err ) {
  146.         err= AECreateAppleEvent( 'misc', 'dmsg', &address, kAutoGenerateReturnID,
  147.                                    kAnyTransactionID, &appleEvent );
  148.         AEDisposeDesc( &address );
  149.         if( !err ) {
  150.             err= AEPutParamPtr( &appleEvent, keyDirectObject, typeChar,
  151.                                  buffer, length );
  152.             if( !err ) {
  153.                 err= AESend( &appleEvent, &reply, 
  154.                          kAEWaitReply + kAENeverInteract,
  155.                          kAENormalPriority, 
  156.                          300,                                 // up to 5 second wait..
  157.                          kODNULL, kODNULL );
  158.                 AEDisposeDesc( &reply );
  159.             }
  160.             AEDisposeDesc( &appleEvent );
  161.         }
  162.     }
  163.     return err;
  164. }
  165.  
  166.  
  167. static short CreateNewOutputFile()
  168. {
  169.     static long    nextFilePrefixNum = 1;
  170.  
  171.     Str255            fileNameRootString = "\pstdout";
  172.     Size            fileNameRootLength = fileNameRootString[0];
  173.     Str255            numString;
  174.     Str255            fileNameString;
  175.     short            file = 0;
  176.  
  177.     CopyPascalString(fileNameString, fileNameRootString);
  178.  
  179.     OSErr err = Create(fileNameRootString, 0, 'MPS ', 'TEXT');
  180.     if (err)
  181.     {
  182.         while(err)
  183.         {
  184.             CopyPascalString(fileNameString, fileNameRootString);
  185.             NumToString(nextFilePrefixNum, numString);
  186.             // check for filename too long.
  187.             if (numString[0] + fileNameRootLength > 255)
  188.             {
  189.                 err = 1;
  190.                 break;
  191.             }
  192.             ConcatPascalStrings(fileNameString, numString);
  193.             err = Create(fileNameString, 0, 'MPS ', 'TEXT');
  194.             ++nextFilePrefixNum;
  195.             if (nextFilePrefixNum > 10000) // arbitrary infinite loop stopper.
  196.                 break;
  197.         }
  198.     }
  199.  
  200.     if (!err)
  201.     {
  202.         err = FSOpen(fileNameString, 0, &file);
  203.         if (err)
  204.             file = 0;
  205.     }
  206.  
  207.     return file;
  208. }
  209.  
  210.  
  211. static ODSShort
  212. ExtractBufferString( ODSShort start, ODSShort end, char output[] )
  213. {
  214.     ODSShort len = end-start;
  215.     if( len >= 0 )
  216.         ODBlockMove(gOutputBuffer+start, output, len);
  217.     else {
  218.         ODSShort len1 = kOutputBufferSize-start;
  219.         ODBlockMove(gOutputBuffer+start, output,len1);
  220.         ODBlockMove(gOutputBuffer, output+len1, end);
  221.         len += kOutputBufferSize;
  222.     }
  223.     output[len] = '\0';
  224.     return len;
  225. }
  226.  
  227.  
  228. static int
  229. OD_SOMOutCharRoutine( char c )
  230. {
  231.     if( c ==0x0A )                    // Convert Unix-style newline to Return
  232.         c = 0x0D;
  233.     
  234.     // Add to buffer, wrapping around:
  235.     gOutputBuffer[gOutputEnd++] = c;
  236.     if( gOutputEnd >= kOutputBufferSize )
  237.         gOutputEnd = 0;
  238.  
  239.     if( c == 0x0D )    {            // Dump buffer at end of line
  240.         if( gOutputMode == kWriteToDebugWindow
  241.                 || gOutputMode == kGenerateDebugStrs
  242.                 || gOutputMode == kWriteToFile)
  243.         {
  244.             // Convert latest output to string:
  245.             char output[kOutputBufferSize+1];
  246.             ODSShort len = ExtractBufferString(gOutputStart,gOutputEnd, output);
  247.                         
  248.             OSErr err = noErr;
  249.         
  250.             if (gOutputMode == kWriteToDebugWindow)
  251.                 err = SendToDebugWindow(output,len);
  252.             else if (gOutputMode == kGenerateDebugStrs)
  253.             {
  254.                 // Convert buffer to pascal string
  255.                 memmove(output + 1, output, len);
  256.                 output[0] = len<=255 ?len :255;
  257.                 DebugStr((StringPtr)output);
  258.             }
  259.             else if (gOutputMode == kWriteToFile)
  260.             {
  261.                 if (gOutputFile == NULL)
  262.                     gOutputFile = CreateNewOutputFile();
  263.                 if (gOutputFile)
  264.                 {
  265.                     long    bytesToWrite = len;
  266.                     err = FSWrite(gOutputFile, &bytesToWrite, output);
  267.                     if (!err && bytesToWrite != len)
  268.                         err = 1;
  269.                 }
  270.                 else
  271.                     err = 1;
  272.             }
  273.     
  274.             if( err )
  275.             {
  276.                 gOutputMode = kGenerateDebugStrs;
  277.                 DebugStr((StringPtr)"\pSOM Message Output: Error writing output -- reverting to DebugStr mode.");
  278.             }
  279.         }
  280.         
  281.         gOutputStart = gOutputEnd;        // "clear" buffer
  282.     }
  283.     
  284.     return 1;
  285. }
  286.  
  287.  
  288. #else /* if not _PLATFORM_MACINTOSH_: */
  289.  
  290.  
  291. static int
  292. OD_SOMOutCharRoutine( char c )
  293. {
  294.     if( gOutputMode == kWriteToFile )
  295.         return gOld_SOMOutCharRoutine(c);
  296.     else
  297.         return 1;
  298. }
  299.  
  300. #endif
  301.  
  302.  
  303. DebugOutputMode
  304. GetOutputMode( )
  305. {
  306.     return gOutputMode;
  307. }
  308.  
  309.  
  310. void
  311. SetOutputMode( DebugOutputMode mode )
  312. {
  313.     if( gOutputMode == kWriteToDebugWindow )
  314.         if( gOutputEnd != gOutputStart )
  315.             OD_SOMOutCharRoutine(0x0D);        // Flush buffer
  316.     gOutputMode = mode;
  317. }
  318.  
  319.  
  320. //=================================================================================== 
  321. // BREAK
  322. //=================================================================================== 
  323.  
  324. void
  325. BREAK( const char msg[] )
  326. {
  327.     somPrintf("%s\n",msg);
  328.     
  329. #ifdef _PLATFORM_MACINTOSH_
  330. #if ODDebug
  331.     // Now convert to Pascal string and call DebugStr:
  332.     Str255 pstr;
  333.     long len = strlen(msg);
  334.     pstr[0] = (len>255) ?255 :len;
  335.     for( int i=pstr[0]; i>0; i-- ) {
  336.         char c = msg[i-1];
  337.         if( c==';' ) c=':';        // ";" is bad in DebugStrs
  338.         pstr[i] = c;
  339.     }
  340.     DebugStr(pstr);
  341. #endif
  342. #endif
  343. }
  344.  
  345.  
  346. //=================================================================================== 
  347. // SOMError
  348. //=================================================================================== 
  349.  
  350. static ODBoolean IsOptionKeyDown()
  351. {
  352.     const ODUShort theKey = 0x3A;    // option key
  353.     unsigned char theKeys[16];
  354.     GetKeys((UInt32*)&theKeys);
  355.  
  356.     return ((theKeys[theKey >> 3] >> (theKey & 7)) & 1);
  357. }
  358.  
  359. static void
  360. OD_SOMError( int error, corbastring filename, int linenum )
  361. {
  362.     const char *kSeverityCode[10] =
  363.                 {"error","warning","message","error?","error?",
  364.                  "error template","error?","error?","error?","fatal error"};
  365.     int base = error / 10000;
  366.     int errno = (error - base*10000) / 10;
  367.     int severity = error % 10;
  368.     
  369.     char msg[kOutputBufferSize+3];
  370.     sprintf(msg, "SOM %s %d-%03d-%d (%s %d): Press G...",
  371.                         kSeverityCode[severity],base,errno,severity,
  372.                         filename,linenum);
  373.     
  374.     if( severity == SOM_Fatal ) {
  375.         somPrintf(msg);
  376.         CUsingLibraryResources r;
  377.         DialogPtr d = kODNULL; ODVolatile(d);
  378.         TRY{
  379.             InitCursor();
  380.             ::Alert(kSOMErrorAlertID,kODNULL);
  381.             if( IsOptionKeyDown() ) {
  382.                 d = ::GetNewDialog(kSOMErrorDlogID,kODNULL,(WindowPtr)-1L);
  383.                 SetDialogDefaultItem(d,ok);
  384.                 SetDialogTextStyle(d,kSOMErrorDlogFontInfo, smCurrentScript);
  385.                 
  386.                 // Copy the entire output buffer, not just the last line:
  387.                 ODSShort start = gOutputEnd;
  388.                 do{
  389.                     ++start;
  390.                     if( start >= kOutputBufferSize ) start=0;
  391.                 }while( start!=gOutputEnd && gOutputBuffer[start]=='\0' );
  392.                 strcpy(msg,"...");
  393.                 ODSShort len = ExtractBufferString(start,gOutputEnd, msg+3) +3;
  394.  
  395.                 short typ;
  396.                 Handle h;
  397.                 Rect box;
  398.                 ::GetDialogItem(d,kSOMErrorDlogTextItem, &typ,&h,&box);
  399.                 PtrToXHand(msg,h,len);
  400.                 
  401.             #if !ODDebug
  402.                 HideDialogItem(d,kSOMErrorDlogDebugButton);
  403.             #endif
  404.                 
  405.                 ShowWindow(d);
  406.                 SelectWindow(d);
  407.                 ODSShort item;
  408.                 ModalDialog(kODNULL,&item);
  409.                 
  410.             #if ODDebug
  411.                 if( item == kSOMErrorDlogDebugButton )
  412.                     Debugger();        // Have a look around...
  413.             #endif
  414.             }
  415.         }CATCH_ALL{
  416.             WARN("Caught error %d displaying SOM error dialog",ErrorCode());
  417.         }ENDTRY
  418.         if( d ) DisposeDialog(d);
  419.         
  420.     } else
  421.         BREAK(msg);                // Nonfatal error: just break
  422.  
  423.     gOld_SOMError(error,filename,linenum);
  424. }
  425.  
  426.  
  427. //=================================================================================== 
  428. // ASSERTION-FAILED
  429. //=================================================================================== 
  430.  
  431. #if ODDebug
  432.  
  433. void _AssertionFailed( char *cond, char *filename,
  434.                         ODError error, char *msg /*=NULL*/ )
  435. {
  436.     char where[300];
  437.     if( ! GetNameOfCaller(where) )
  438.         strcpy(where,filename);
  439.         
  440.     ODUnused(filename);
  441.     char dbg[256];
  442.     if( msg )
  443.         sprintf(dbg,"%s: %s ...NOT! At %s", msg,cond,where); 
  444.     else
  445.         sprintf(dbg,"%s ...NOT! At %s", cond,where); 
  446.     BREAK(dbg);
  447.     
  448.     if( error!=0 )
  449.         THROW(error, msg ?msg :"Assertion failed");
  450. }
  451.  
  452. #else /*not ODDebug*/
  453.  
  454. extern "C" void _AssertionFailed(  char *cond, char *filename,
  455.                         ODError error, char *msg );
  456. void _AssertionFailed( char *cond, char *filename,
  457.                         ODError error, char *msg )
  458. {
  459. }
  460.     
  461. #endif /*ODDebug*/
  462.     
  463.     
  464. //=================================================================================== 
  465. // WARN
  466. //=================================================================================== 
  467.  
  468. #if ODDebug
  469.  
  470. void _Warn( char *fmt, ... )
  471. {
  472.     char msg[512];
  473.     strcpy(msg, "ODWarning: ");
  474.     va_list args;
  475.     va_start(args,fmt);
  476.     vsprintf(msg+strlen(msg),fmt,args);
  477.     va_end(args);
  478.     
  479.     char caller[300];
  480.  
  481.     // DMc: make sure _Warn() cannot throw an exception (out-of-memory when a stack
  482.     // crawl is allocated), because _Warn is often called in unsafe contexts that
  483.     // are not protected by a TRY block:
  484.     TRY {
  485.         if( GetNameOfCaller(caller) ) {
  486.             strcat(msg," (at ");
  487.             strcat(msg,caller);
  488.             strcat(msg,")");
  489.         }
  490.     } CATCH_ALL {
  491.     } ENDTRY
  492.     
  493.     BREAK(msg);
  494. }
  495.     
  496. #else /*not ODDebug*/
  497.  
  498. extern "C" void _Warn(  char *fmt, ... );
  499. void _Warn(  char *fmt, ... )
  500. {
  501. }
  502.  
  503. #endif /*ODDebug*/
  504.     
  505. //==============================================================================
  506. // SAFE CAST
  507. //==============================================================================
  508.  
  509.  
  510. #if ODDebug
  511.  
  512. SOMObject*
  513. _Cast( SOMObject *obj, somClassDataStructure *clsdata, long majorversion, long minorversion )
  514. {
  515.     SOMClass *cls = (SOMClass*) somGetStaticClassReference(clsdata,majorversion,minorversion);
  516.     if( !somIsObj(obj) )
  517.         WARN("Can't cast: %p is not a SOM object",obj);
  518.     else if( !somIsObj(cls) )
  519.         WARN("Can't cast: %p is not a SOM class",cls);
  520.     else if( !obj->somIsA(cls) )
  521.         WARN("Can't cast: %p is an %s, not an %s",obj, obj->somGetClassName(), cls->somGetName());
  522.     else {
  523.         somReleaseClassReference(cls);
  524.         return obj;
  525.     }
  526.     somReleaseClassReference(cls);
  527.     THROW(kODErrAssertionFailed);
  528.     return NULL; /* keeps compiler quiet */
  529. }
  530.  
  531. #else /*not ODDebug*/
  532.  
  533. extern "C" void _Cast( );
  534. void _Cast( )
  535. {
  536. }
  537.     
  538. #endif /*ODDebug*/
  539.